iT邦幫忙

2022 iThome 鐵人賽

DAY 24
0
Modern Web

終究都要學 React 何不現在學呢?系列 第 24

終究都要學 React 何不現在學呢? - React Router - 基礎與介紹 - (24)

  • 分享至 

  • xImage
  •  

前言

雖然在極小的專案下,前面章節所學的知識點是很足夠的,但是我們在真正的專案開發上不可能只用前面的知識點而已,因為頁面會隨著專案規模大小越來越複雜,因此我們需要一個能夠幫助我們管理頁面的工具,而這個工具就是 React Router。

什麼是 React Router?

React Router 是什麼呢?在說明 React Router 這個之前想先簡單講一個觀念,也就是所謂的 SPA(Single Page Application,中文又稱單頁式應用程式)。

那麼 SPA 是什麼呢?SPA 是一個 Web 開發實作...

...
.....
.......

好,暫停一下,其實這一段開始有點文謅謅了,所以我就簡單解釋就好,其實就是從頭到尾你都在同一頁面的意思,什麼叫做同一頁面呢?後面會慢慢解釋。

剛剛有提到 SPA 中文是「單頁式應用程式」其實就是你從頭到尾都在 index.html 這個頁面上,因此如果是採用 SPA 模式開發的網站,那麼你在瀏覽器的網址列上可能會看到這種形式

https://www.example.com/#/

而這一串就是透過 JavaScript 模擬後端路由形成的 SPA 網頁,那你可能會想說 index.html 呢?怎麼消失了?通常來講 「/」默認是 index.html,因此才可以忽略,但也是有一些網站默認是 default.htmlhome.html,而這一段是可以透過伺服器的設置來決定默認首頁是哪一個,但通常默認會是 index.html

那麼在 SPA 還沒有流行之前,早期都是使用 MPA (Multi Page Application,中文又稱多頁式應用程式)的方式開發,所以你會看到瀏覽器網址列像這樣子呈現

https://www.example.com/user/profile

而不會有 /#/ 的形式,因為一段 #/ 就是由前端模擬後端路由的一種形式,雖然也可以調整成類似 MPA 的路由形式,但這個必須要與後端搭配才可以,因此 SPA 開發上大多還是以 /#/ 模擬為主,而這種模式又稱之為 hash mode

但這一點並不是我們要了解的知識,如果想更深入了解的話,可以考慮閱讀我先前寫的這一篇 淺談 SPA、CSR、SSR、MPA、SSG 專有名詞

那麼前面對於 SPA 有一個簡單基本概念之後 React Router 就是要幫助我們做這件事情的重要核心,因此接下來你可以打開任何一個專案,例如前面章節我們所建立的 Vite TodoList 專案也可以,並在終端機輸入以下指令安裝 React Router

npm install --save react-router-dom

而這邊我會使用前面所建立的 example-vite-react 當作示範,你也可以趁機會現在下載或者建立一個新專案。

React Router 起手式

首先第一個步驟先打開 App.jsx 引入 import { HashRouter } from "react-router-dom";,而這個 HashRouter 本身就是一個元件概念,接著只需要使用它將整個 <App /> 包起來即可

import React from 'react'
import { HashRouter } from "react-router-dom";
import ReactDOM from 'react-dom/client'
import App from './App'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <HashRouter>
      <App />
    </HashRouter>
  </React.StrictMode>
)

恭喜你!你已經成功引入了 React Router 囉!接下來我們就可以開始使用它了。

React Router 基本使用

接下來我們要來認識另一個東西,也就是 Route

Route 主要是用來定義路徑跟 Components 之間的關係,你也可以把它想像成「綁定」的概念,舉例來講如果你希望使用者訪問的路徑是以下

https://www.example.com/#/todolist

那麼你在使用 Route 的時候就可以這樣寫

<Route path="/todolist" element={ <ToDoList/> }>

而常見的屬性主要會有兩個

  • path:定義路徑
  • element:定義對應的元件

到目前為止,這是一個基本的 Route 使用方式。

事不宜遲,就來把原本寫在 App.jsx 的 ToDoList 挪出來放到另一個元件內,例如叫做 ToDoList.jsx,而 App.jsx 則改成以下

const App = () => {
  return (
    <h1>App</h1>
  )
}

export default App;

接下來就是打開 main.jsx 引入 ToDoList.jsx 並搭配 Route 一起使用

import React from 'react'
import { HashRouter, Route } from "react-router-dom";
import ReactDOM from 'react-dom/client'
import App from './App'
import './index.css'

import ToDoList from "./TodoList";

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <HashRouter>
      <Route path="/" element={ <App /> } />
      <Route path="/todolist" element={ <ToDoList /> } />
    </HashRouter>
  </React.StrictMode>
)

接下來當你輸入 npm run dev 啟動專案,並在瀏覽器上輸入 http://localhost:3000/#/todolist 你會發現畫面一片空白,並且控制台會出現以下錯誤訊息

Uncaught Error: A <Route> is only ever to be used as the child of <Routes> element, never rendered directly. Please wrap your <Route> in a <Routes>.

這邊我是刻意示範一個錯誤的寫法,其實簡單來講 <Route> 只能包在 <Routes> 底下使用,因此正確來講必須這樣寫才對

import React from 'react'
import { HashRouter, Route, Routes } from "react-router-dom";
import ReactDOM from 'react-dom/client'
import App from './App'
import './index.css'
import ToDoList from "./TodoList";

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <HashRouter>
      <Routes>
        <Route path="/" element={ <App /> } />
        <Route path="/todolist" element={ <ToDoList /> } />
      </Routes>
    </HashRouter>
  </React.StrictMode>
)

接下來你重新 npm run dev 的時候應該會看到滿空白的,只有很孤單寂寞覺得冷的一段話「App」,這是很正常的,因為首頁就是這樣子。

但...我們該如何進入 todolist 呢?你可以先試著在瀏覽器網址列輸入 http://localhost:3000/#/todolist,這樣子你就可以看到「ToDoList」出現在畫面上囉。

那麼今天就先到這邊結束,後面我們還會繼續講解 React Router 的其他使用方式,例如 巢狀路由、LinkNavLink 等等。

範例程式碼:React Router Example

後記

本文將會同步更新到我的部落格


上一篇
終究都要學 React 何不現在學呢? - React Vite - Vite 淺談與 GitHub 部署 - (23)
下一篇
終究都要學 React 何不現在學呢? - React Router - 巢狀路由 - (25)
系列文
終究都要學 React 何不現在學呢?30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言